package camp

import (
	"github.com/pkg/errors"
	"sync/atomic"
)
var firstP *pair = &pair{}
type Bucket interface {
	Put(pair Pair)(bool,error)
	Get(key string)Pair
	Delete(key string)bool
	Clear()
	GetFirstPair()Pair
	Size()uint64
}

type bucket struct {
	firstValue atomic.Value
	size uint64
}

func (this *bucket)GetFirstPair()Pair  {
	if v := this.firstValue.Load();v == nil{
		return nil
	}else if p,ok:= v.(Pair);!ok || p==firstP{
		return nil
	}else{
		return p
	}
}
func(this *bucket)Put(pair Pair)(bool,error){
	if pair == nil{
		return false,errors.New("parasm is nil")
	}
	first := this.GetFirstPair()
	if first == nil{
		this.firstValue.Store(pair)
		atomic.AddUint64(&this.size,1)
		return true,nil
	}
	var target Pair
	key := pair.Key()
	for v := first; v != nil; v = v.Next(){
		if v.Key() == key{
			target = v
			break
		}
	}
	if target != nil{
		target.SetElement(pair.Element())
		return true,nil
	}
	pair.SetNext(first)
	this.firstValue.Store(pair)
	atomic.AddUint64(&this.size,1)
	return true,nil
}
func (this *bucket)Get(key string)Pair  {
	first := this.GetFirstPair()
	for v:=first;v!=nil;v=v.Next(){
		if v.Key()== key{
			return v
		}
	}
	return nil
}
func (this *bucket)Delete(key string)bool  {
	if this.Size() == 0{
		return true
	}
	var pre []Pair
	var target Pair
	for v:=this.GetFirstPair();v !=nil;v=v.Next(){
		if v.Key() == key{
			target = v
			break
		}
		pre =  append(pre,v)
	}
	if target == nil{
		return false
	}
	newPair := target.Next()
	for len := len(pre)-1;len>=0;len--{
		 pp := pre[len].Copy()
		 pp.SetNext(newPair)
		 newPair = pp
	}
	if newPair == nil{
		this.firstValue.Store(firstP)
	}else{
		this.firstValue.Store(newPair)
	}
	atomic.AddUint64(&this.size,^uint64(0))
	return  true
}
func (this *bucket)Clear()  {
	this.firstValue.Store(firstP)
	atomic.StoreUint64(&this.size,0)
}
func (this *bucket)Size()uint64  {
	return atomic.LoadUint64(&this.size)
}
func NewBucket() Bucket {
	b := &bucket{}
	b.firstValue.Store(firstP)
	return b
}